package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.order.factory.GuiguItemType;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 专辑订单的实现类
 */
@Slf4j
@Service(value = "albumOrderInfoServiceImpl")
@SuppressWarnings({"unchecked", "rawtypes"})
@GuiguItemType(itemType = SystemConstant.ORDER_ITEM_TYPE_ALBUM)
public class AlbumOrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Resource
    private OrderInfoMapper orderInfoMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Resource
    private OrderDerateMapper orderDerateMapper;

    @Resource
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Resource
    public RSAPrivateKey rsaPrivateKey;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // @Override
    // public String getItemType() {
    //     return SystemConstant.ORDER_ITEM_TYPE_ALBUM;
    // }

    /**
     * 订单确认接口
     * @param tradeVo
     * @return
     */
    @Override
    public Object trade(TradeVo tradeVo) {
        // System.out.println("购买专辑触发");
        // 获取专辑的id
        Long itemId = tradeVo.getItemId();
        // 查询专辑的详细信息
        AlbumInfo albumInfo = albumInfoFeignClient.getAlbumInfo(itemId);
        // 非空判断 redis中可能存在空的专辑对象
        if (albumInfo == null || albumInfo.getId() == null){
            throw new GuiguException(201, "专辑不存在, 无法确认下单");
        }

        //包装订单对象: 不入库!!!!!!!!!!!!!!
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //交易号
        orderInfoVo.setTradeNo(IdWorker.get32UUID());
        //支付方式: 默认为微信
        orderInfoVo.setPayWay("1101");
        //购买的类型
        orderInfoVo.setItemType(SystemConstant.ORDER_ITEM_TYPE_ALBUM);
        //原始金额
        BigDecimal price = albumInfo.getPrice();
        orderInfoVo.setOriginalAmount(price);
        // 查询用户是否为VIP
        //方案一: feign: 慢一点
        // UserInfo userInfo = userInfoFeignClient.getUserInfo(AuthContextHolder.getUserId());
        // Integer isVip = userInfo.getIsVip();
        //方案二: 从本地线程获取: 快一点
        Integer isVip = AuthContextHolder.getIsVip();
        // 计算订单金额
        BigDecimal disCount = null;
        if (isVip.equals(0)){
            // 普通折扣
            disCount = albumInfo.getDiscount();
        } else {
            // VIP折扣
            disCount = albumInfo.getVipDiscount();
        }
        // 获取具体的折扣 0.1-9.9  不打折 -1
        disCount = disCount.intValue() == -1 ? new BigDecimal(1) : new BigDecimal("0.1").multiply(disCount);
        // 计算专辑订单的金额
        price = price.multiply(disCount);
        orderInfoVo.setOrderAmount(price);
        // 计算订单的减免金额 = 原价 - 实付价格(订单价格)
        orderInfoVo.setDerateAmount(orderInfoVo.getOriginalAmount().subtract(orderInfoVo.getOrderAmount()));

        //声明订单的详细对象(专辑)
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        OrderDetailVo orderDetailVo = new OrderDetailVo();
        orderDetailVo.setItemId(itemId);
        orderDetailVo.setItemName(albumInfo.getAlbumTitle());
        orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
        orderDetailVo.setItemPrice(orderInfoVo.getOrderAmount());

        orderDetailVoList.add(orderDetailVo);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);

        //声明订单的减免详情
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        OrderDerateVo orderDerateVo = new OrderDerateVo();
        orderDerateVo.setDerateType("1405");
        orderDerateVo.setDerateAmount(orderInfoVo.getDerateAmount());
        orderDerateVo.setRemarks("专辑折扣!!");

        orderDerateVoList.add(orderDerateVo);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);

        //时间戳
        orderInfoVo.setTimestamp(System.currentTimeMillis());

        // 使用私钥签名 确保订单信息不会被篡改
        Jwt encode = JwtHelper.encode(JSONObject.toJSONString(orderInfoVo), new RsaSigner(rsaPrivateKey));
        orderInfoVo.setSign(encode.getEncoded());
        //返回订单对象
        return orderInfoVo;
    }

    /**
     * 提交订单: 写入数据库
     * @param orderInfoVo
     * @return
     */
    @Override
    public Object submitOrder(OrderInfoVo orderInfoVo) {
        // 获取当前登录用户id
        Long userId = AuthContextHolder.getUserId();
        // 用公钥尝试获取签名 成功则获取到载荷中的信息 失败则报异常
        String sign = orderInfoVo.getSign();
        try {
            Jwt jwt = JwtHelper.decodeAndVerify(sign, new RsaVerifier(SystemConstant.PUBLIC_KEY));
            // 获取载荷
            String claims = jwt.getClaims();
            // 反序列化 获得载荷中的信息
            orderInfoVo = JSONObject.parseObject(claims, OrderInfoVo.class);
        } catch (Exception e) {
            throw new GuiguException(201, "非法参数, 请重新下单");
        }
        // 获取专辑的id 由于是从签名中解析出来的 所以是可信的
        Long itemId = orderInfoVo.getOrderDetailVoList().get(0).getItemId();

        // 专辑订单提交锁 防止高并发场景下频繁提交订单  15分钟后自动过期 付费专辑和单集收费专辑的id一定不会重复
        if(redisTemplate.opsForValue().setIfAbsent(userId + "_" + itemId, "album", 15, TimeUnit.MINUTES)){

          //判断用户的未支付/已支付订单中是否存在该专辑: 防止用户重复买同一个专辑
          Integer count = orderInfoMapper.selectOrderCountAlbum(itemId, userId);
          if(count > 0){
            throw new GuiguException(201, "专辑订单已存在,请勿重复购买!");
          }
          //签名合法,包装DO的订单数据
          OrderInfo orderInfo = new OrderInfo();
          BeanUtils.copyProperties(orderInfoVo, orderInfo);
          //补全用户ID
          orderInfo.setUserId(AuthContextHolder.getUserId());
          //补全订单no
          orderInfo.setOrderNo(orderInfoVo.getTradeNo());
          //补全订单的描述
          orderInfo.setOrderTitle("专辑订单" + itemId);
          //保存订单的数据
          if(orderInfoMapper.insert(orderInfo) <= 0){
            throw new GuiguException(201, "新增订单失败");
          }
          //获取订单id
          Long orderId = orderInfo.getId();
          //保存订单详情
          orderInfoVo.getOrderDetailVoList().stream().forEach(vo->{
            //初始化详情的DO
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(vo, orderDetail);
            //补全orderId
            orderDetail.setOrderId(orderId);
            //新增
            if(orderDetailMapper.insert(orderDetail) <= 0){
              throw new GuiguException(201, "新增订单失败!!!");
            }
          });
          //保存订单的减免详情
          List<OrderDerateVo> orderDerateVoList =
                  orderInfoVo.getOrderDerateVoList();
          if(orderDerateVoList != null){
            orderDerateVoList.stream().forEach(vo->{
              //初始化减免的DO
              OrderDerate orderDerate = new OrderDerate();
              BeanUtils.copyProperties(vo, orderDerate);
              //补全orderId
              orderDerate.setOrderId(orderId);
              //新增
              if(orderDerateMapper.insert(orderDerate) <= 0){
                throw new GuiguException(201, "新增订单失败!!!");
              }
            });
          }
          //返回结果初始化
          JSONObject result = new JSONObject();
          result.put("orderNo", orderInfo.getOrderNo());
          // 订单提交成功后 会被放入延迟队列 持续15分钟
          //入库时间点开始,订单支付倒计时:15分钟(10分钟): a.定时任务方案  b.延迟消息方案(最终方案)
          rabbitTemplate.convertAndSend(
                  "tingshu_order_exchange",
                  "tingshu.order",
                  orderId + "", // 订单的主键
                  message -> {
                    //获取消息的属性
                    MessageProperties messageProperties = message.getMessageProperties();
                    //设置过期时间:毫秒
                    messageProperties.setExpiration("900000"); // 900秒(15分钟)
                    // messageProperties.setExpiration("20000"); // 20秒
                    //返回
                    return message;
                  });
          //返回
          return result;

        }
        throw new GuiguException(201, "该专辑存在一笔未支付订单");

    }

  @Override
  public Object selectUserOrderPage(Integer page, Integer size) {
    return null;
  }

  @Override
  public OrderInfo getOrderInfo(String orderNo) {
    return null;
  }
}
